package com.lwc.cfdns.config;

import com.lwc.cfdns.constants.ConstantsUrl;
import com.lwc.cfdns.filter.JwtAuthenticationTokenFilter;
import com.lwc.cfdns.pojo.security.AccessDeniedHandlerImpl;
import com.lwc.cfdns.pojo.security.AuthenticationEntryPointImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * security配置类
 * https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter#ldap-authentication
 *
 * @author luwc
 * @title SecurityConfig
 * @description
 * @time 2023/5/10 17:45:26
 * @version: 1.0
 */
@Configuration
@EnableWebSecurity
// 开启权限配置注释功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    @Autowired
    private AccessDeniedHandlerImpl accessDeniedHandler;
    @Autowired
    private AuthenticationEntryPointImpl authenticationEntryPoint;

    /**
     * 密码加密器，会把客户端传来的密码进行加密，然后跟数据库中的密码做对比，要求数据库中的密码也是加密过的
     * 如果没有该加密器，spring security会报出异常：There is no PasswordEncoder mapped for the id "null"
     *
     * @param
     * @return PasswordEncoder
     * @throws
     * @version 1.0.0
     * @author luwc
     * @time 2023/5/10 17:51:57
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 获取AuthenticationManager（认证管理器），登录时认证使用
     *
     * @param authenticationConfiguration
     * @return AuthenticationManager
     * @throws
     * @version 1.0.0
     * @author luwc
     * @time 2023/5/10 17:51:52
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }

    /**
     * Security核心配置
     *
     * @param security
     * @return SecurityFilterChain
     * @throws
     * @version 1.0.0
     * @author luwc
     * @time 2023/5/10 17:55:53
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity security) throws Exception {
        return security
                // 关闭csrf
                .csrf().disable()
                .cors()// Security跨域
                .and()
                // 基于 token，不需要 session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling()
                // 设置处理认证失败
                .authenticationEntryPoint(authenticationEntryPoint)
                // 设置处理鉴权失败
                .accessDeniedHandler(accessDeniedHandler)
                .and()
                .authorizeRequests(authorize -> authorize
                                // API模块都允许
                                .antMatchers(ConstantsUrl.API + "/**").anonymous()
                                // spring-boot-admin-client允许
                                .antMatchers("/actuator/**").anonymous()
                                // Admin模块
                                // 登录接口、静态资源肯定是不需要认证的
                                .antMatchers(ConstantsUrl.ADMIN + "/common/login", AttachmentLocalConfig.getUploadPath() + "**").anonymous()
                                .anyRequest().authenticated()
//                .anyRequest().permitAll()//除了/r/**，其它的请求可以访问
                )
                // 注册过滤器
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }

    /**
     * 配置跨源访问(CORS)
     * @return
     */
//    @Bean
//    CorsConfigurationSource corsConfigurationSource() {
//        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
//        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
//        return source;
//    }
}
